using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using UniversalAdmin.Domain.Entities;
using UniversalAdmin.Domain.Interfaces;
using UniversalAdmin.Infrastructure.Data.Contexts;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace UniversalAdmin.Infrastructure.Services
{
    public class JwtService : IJwtService
    {
        private readonly IConfiguration _config;
        private readonly ApplicationDbContext _db;
        private readonly ILogger<JwtService> _logger;

        public JwtService(IConfiguration config, ApplicationDbContext db, ILogger<JwtService> logger)
        {
            _config = config ?? throw new ArgumentNullException(nameof(config));
            _db = db ?? throw new ArgumentNullException(nameof(db));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        }

        // 原方法保留，内部调新重载，默认 2 小时
        public string GenerateToken(User user)
            => GenerateToken(user, rememberMe: false);

        // 新重载：根据 rememberMe 决定过期时间
        /// <summary>
        /// 生成JWT Token - 性能优化版本
        /// </summary>
        /// <param name="user">用户对象，包含Id、Username、Email等信息</param>
        /// <param name="rememberMe">是否记住用户（延长Token有效期）</param>
        /// <returns>生成的JWT Token字符串</returns>
        public string GenerateToken(User user, bool rememberMe)
        {
            if (user == null)
                throw new ArgumentNullException(nameof(user));

            _logger.LogInformation("开始生成JWT Token，用户ID: {UserId}, 记住我: {RememberMe}", user.Id, rememberMe);
            
            // 从配置读取过期时间（分钟），并根据rememberMe调整
            var expireMinutes = int.Parse(_config["Jwt:ExpireMinutes"] ?? "1440");
            var expires = rememberMe
                ? DateTime.UtcNow.AddMinutes(expireMinutes)  // 使用配置的24小时
                : DateTime.UtcNow.AddMinutes(120);          // 不记住：2小时

            var keyString = _config["Jwt:Key"] ?? throw new InvalidOperationException("JWT密钥未配置");
            _logger.LogDebug("使用JWT密钥长度: {KeyLength} 字符", keyString.Length);
            
            // 缓存密钥对象以避免重复创建
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(keyString));

            // 创建签名凭证（使用HmacSha256算法）
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

            // 定义Token中的用户声明（Claims）
            var claims = new[]
            {
                new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()), // 用户唯一标识
                new Claim(ClaimTypes.Name, user.Username),                 // 用户名
                new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64) // 颁发时间戳
            };

            // 生成JWT Token
            var token = new JwtSecurityToken(
                issuer: _config["Jwt:Issuer"] ?? "UniversalAdmin",     // 发行者
                audience: _config["Jwt:Audience"] ?? "UniversalAdmin", // 受众
                claims: claims,                     // 用户声明
                notBefore: DateTime.UtcNow,        // 生效时间
                expires: expires,                  // 过期时间
                signingCredentials: creds);        // 签名凭证

            var tokenString = new JwtSecurityTokenHandler().WriteToken(token);
            _logger.LogInformation("JWT Token生成成功，用户ID: {UserId}, Token长度: {TokenLength}", user.Id, tokenString.Length);
            
            return tokenString;
        }

        /// <summary>
        /// 验证并解析 JWT Token
        /// </summary>
        public bool ValidateToken(string token)
        {
            if (string.IsNullOrEmpty(token))
            {
                _logger.LogWarning("Token为空或null");
                return false;
            }

            _logger.LogInformation("开始验证JWT Token，Token长度: {TokenLength}", token.Length);
            
            var handler = new JwtSecurityTokenHandler();
            var keyString = _config["Jwt:Key"] ?? throw new InvalidOperationException("JWT密钥未配置");
            var key = Encoding.UTF8.GetBytes(keyString);

            try
            {
                var validationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(key),
                    ValidateIssuer = true,
                    ValidIssuer = _config["Jwt:Issuer"] ?? "UniversalAdmin",
                    ValidateAudience = true,
                    ValidAudience = _config["Jwt:Audience"] ?? "UniversalAdmin",
                    ValidateLifetime = true,
                    ClockSkew = TimeSpan.Zero
                };

                _logger.LogDebug("Token验证参数配置: Issuer={Issuer}, Audience={Audience}, KeyLength={KeyLength}", 
                    _config["Jwt:Issuer"], _config["Jwt:Audience"], keyString.Length);

                var principal = handler.ValidateToken(token, validationParameters, out var validatedToken);
                _logger.LogInformation("JWT Token验证成功，用户: {UserName}", 
                    principal.FindFirst(ClaimTypes.NameIdentifier)?.Value);
                
                return true;
            }
            catch (SecurityTokenExpiredException ex)
            {
                _logger.LogWarning("JWT Token已过期: {Message}", ex.Message);
                return false;
            }
            catch (SecurityTokenInvalidSignatureException ex)
            {
                _logger.LogError("JWT Token签名验证失败: {Message}", ex.Message);
                return false;
            }
            catch (SecurityTokenInvalidIssuerException ex)
            {
                _logger.LogError("JWT Token发行者验证失败: {Message}", ex.Message);
                return false;
            }
            catch (SecurityTokenInvalidAudienceException ex)
            {
                _logger.LogError("JWT Token受众验证失败: {Message}", ex.Message);
                return false;
            }
            catch (Exception ex)
            {
                _logger.LogError("JWT Token验证失败: {Message}, 堆栈: {StackTrace}", ex.Message, ex.StackTrace);
                return false;
            }
        }

        /// <summary>
        /// 异步验证Token（简化版，移除黑名单检查）
        /// </summary>
        public Task<bool> ValidateTokenAsync(string token)
        {
            // 仅进行常规JWT验证，不再检查黑名单
            var result = ValidateToken(token);
            return Task.FromResult(result);
        }

        /// <summary>
        /// 从令牌中获取用户ID
        /// </summary>
        /// <param name="token">JWT令牌</param>
        /// <returns>用户ID</returns>
        public Task<string> GetUserIdFromTokenAsync(string token)
        {
            if (string.IsNullOrEmpty(token))
            {
                _logger.LogWarning("Token为空或null");
                return Task.FromResult(string.Empty);
            }

            try
            {
                var principal = GetClaimsPrincipalFromToken(token);
                var userIdClaim = principal?.FindFirst(ClaimTypes.NameIdentifier);
                var userId = userIdClaim?.Value ?? string.Empty;
                
                _logger.LogInformation("从Token中获取用户ID成功: {UserId}", userId);
                return Task.FromResult(userId);
            }
            catch (Exception ex)
            {
                _logger.LogError("从Token中获取用户ID失败: {Message}", ex.Message);
                return Task.FromResult(string.Empty);
            }
        }

        /// <summary>
        /// 从令牌中获取ClaimsPrincipal
        /// </summary>
        /// <param name="token">JWT令牌</param>
        /// <returns>ClaimsPrincipal</returns>
        private ClaimsPrincipal? GetClaimsPrincipalFromToken(string token)
        {
            if (string.IsNullOrEmpty(token))
            {
                _logger.LogWarning("Token为空或null");
                return null;
            }

            _logger.LogInformation("开始解析JWT Token，Token长度: {TokenLength}", token.Length);
            
            var handler = new JwtSecurityTokenHandler();
            var keyString = _config["Jwt:Key"] ?? throw new InvalidOperationException("JWT密钥未配置");
            var key = Encoding.UTF8.GetBytes(keyString);

            try
            {
                var validationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(key),
                    ValidateIssuer = true,
                    ValidIssuer = _config["Jwt:Issuer"] ?? "UniversalAdmin",
                    ValidateAudience = true,
                    ValidAudience = _config["Jwt:Audience"] ?? "UniversalAdmin",
                    ValidateLifetime = true,
                    ClockSkew = TimeSpan.Zero
                };

                var principal = handler.ValidateToken(token, validationParameters, out var validatedToken);
                _logger.LogInformation("JWT Token解析成功，用户: {UserName}", 
                    principal.FindFirst(ClaimTypes.NameIdentifier)?.Value);
                
                return principal;
            }
            catch (Exception ex)
            {
                _logger.LogError("JWT Token解析失败: {Message}, 堆栈: {StackTrace}", ex.Message, ex.StackTrace);
                return null;
            }
        }
    }
}